home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_300 / 330_03 / tskprt.c < prev    next >
C/C++ Source or Header  |  1990-10-10  |  11KB  |  411 lines

  1. /*
  2.    --- Version 2.2 90-10-12 10:33 ---
  3.  
  4.    TSKPRT.C - CTask - Printer interface routines.
  5.  
  6.    Public Domain Software written by
  7.       Thomas Wagner
  8.       Ferrari electronic Gmbh
  9.       Beusselstrasse 27
  10.       D-1000 Berlin 21
  11.       Germany
  12.  
  13.    The algorithm for waiting when the printer is busy has been changed
  14.    in version 1.2. In the previous versions, a timed delay was used after
  15.    a certain number of times through the loop. Depending on the kind of
  16.    printer, and the system speed, this could lead to extremely slow
  17.    output. Now a busy waiting loop with scheduling is employed. This
  18.    change will not likely hamper system performance significantly, but
  19.    can speed up printer output processing.
  20.  
  21.    Also new in version 1.2 is the stack switch module, tskprti.asm. The
  22.    interrupt routine is now called through an "envelope" that first
  23.    switches to a local stack.
  24. */
  25.  
  26.  
  27. #include "tsk.h"
  28. #include "tsklocal.h"
  29. #include "prt.h"
  30.  
  31. #if (DOS)
  32.  
  33. #define STKSZ     256   /* Printer Task stack size */
  34.  
  35. /*
  36.    The following values may need some tuning for optimum performance.
  37. */
  38. /* 
  39.    MAX_WAIT_xx: Maximum number of times through the loop when waiting
  40.                 for the printer to get ready.
  41. */
  42.  
  43. #define MAX_WAIT_INT    30 /* For interrupt output */
  44. #define MAX_WAIT_POLL   30 /* For polling output */
  45.  
  46. #if (CLOCK_MSEC)
  47. #define INT_TIMEOUT  100L  /* Timeout for ACK interrupt wait */
  48. #else
  49. #define INT_TIMEOUT  2L    /* Timeout for ACK interrupt wait */
  50. #endif
  51.  
  52.  
  53.  
  54. #define inta00    0x20   /* 8259 interrupt controller control-port */
  55. #define inta01    0x21   /* 8259 interrupt controller mask-port */
  56.  
  57. #define rdserv    0x0b   /* read service register control value */
  58. #define eoi       0x20   /* end of interrupt signal for 8259 */
  59.  
  60. #define data      0x00
  61. #define status    0x01
  62. #define control   0x02
  63.  
  64. #define STROBE    0x01
  65. #define IRQENA    0x10
  66.  
  67. #define dflt_control    (INIT | SELECT)
  68.  
  69.  
  70. /*
  71.    To add support for other LPT-Ports, define
  72.       - Port base
  73.       - IRQ-Bit (optional)
  74.       - Interrupt vector (optional)
  75.    here, add the necessary data to the pr_port_descr array, and, if irq
  76.    was specified, define the corresponding interrupt function by 
  77.    duplicating prtint0, replacing the index into the prt_data array.
  78. */
  79.  
  80. #define PORTS  3              /* Number of defined ports */
  81.  
  82. #define lpt1_base    0x3bc    /* LPT1 port base (mono card) */
  83. #define lpt2_base    0x378    /* LPT2 port base (IBM printer adapter) */
  84. #define lpt3_base    0x278    /* LPT3 port base (secondary parallel) */
  85.  
  86. #define lpt1_irq     0x80     /* IRQ-Bit for LPT1 */
  87. #define lpt2_irq     0x80     /* IRQ-Bit for LPT2 (same as LPT1) */
  88. #define lpt3_irq     0x20     /* IRQ-Bit for LPT3 */
  89.  
  90. #define lpt1_vect    0x0f     /* Interrupt vector for LPT1 */
  91. #define lpt2_vect    0x0f     /* Interrupt vector for LPT2 */
  92. #define lpt3_vect    0x0d     /* Interrupt vector for LPT3 */
  93.  
  94. typedef struct {
  95.                intprocptr  proc;
  96.                int         base;
  97.                byte        irq;
  98.                byte        vector;
  99.                } port_data;
  100.  
  101. extern void interrupt far tskprt_int0 (void);
  102. extern void interrupt far tskprt_int1 (void);
  103. extern void interrupt far tskprt_int2 (void);
  104.  
  105. port_data pr_port_descr [PORTS] = {
  106.                              { tskprt_int0, lpt1_base, lpt1_irq, lpt1_vect },
  107.                              { tskprt_int1, lpt2_base, lpt2_irq, lpt2_vect },
  108.                              { tskprt_int2, lpt3_base, lpt3_irq, lpt3_vect }
  109.                                   };
  110.  
  111. /*-------------------------------------------------------------------------*/
  112.  
  113. typedef struct {
  114.                intprocptr savvect;     /* Interrupt vector save location */
  115.                int      port_base;     /* Port base I/O address */
  116.                byte     irqbit;        /* IRQ-Bit for this port */
  117.                byte     civect;        /* Interrupt Vector for this port */
  118.                byte     wait_xmit;     /* Transmit delayed */
  119.                byte     xmit_pending;  /* Transmit in progress */
  120.                byte     polling;       /* Use polling if on */
  121.                byte     ccontrol;      /* Current control reg */
  122.                pipe     xmit_pipe;     /* Transmit pipe */
  123.                flag     pready;        /* Printer ready flag */
  124.                tcb      pr_task;       /* Printer task */
  125.                byte     pr_stack [STKSZ]; /* Printer task stack */
  126.                } prt_datarec;
  127.  
  128. typedef prt_datarec *prtptr;
  129.  
  130. local prt_datarec prt_data [PORTS];
  131. local int prt_installed [PORTS] = { 0 };
  132. local callchain remove_chain = { LNULL, LNULL };
  133.  
  134. /*-------------------------------------------------------------------------*/
  135.  
  136.  
  137. void Localfunc tsk_prt_int (int port)
  138. {
  139.    prtptr prt = &prt_data [port];
  140.  
  141.    /* Turn off int */
  142.    prt->ccontrol &= ~IRQENA;
  143.    tsk_outp (prt->port_base + control, prt->ccontrol);
  144.  
  145.    /* Signal print char complete */
  146.    set_flag (&prt->pready);
  147. }
  148.  
  149.  
  150. /*-------------------------------------------------------------------------*/
  151.  
  152.  
  153. local void Staticfunc pr_toggle_strobe (int port_base, byte ctl)
  154. {
  155.    tsk_outp (port_base + control, ctl | STROBE);
  156.    tsk_nop ();
  157.    tsk_outp (port_base + control, ctl);
  158. }
  159.  
  160. local int Staticfunc pr_ready (int port_base)
  161. {
  162.    return (tsk_inp (port_base + status) & (BUSY | ACK | PEND | SELIN | ERROR))
  163.           == (BUSY | ACK | SELIN | ERROR);
  164. }
  165.  
  166.  
  167. local void Staticfunc pr_output_poll (prtptr prt, byte ch)
  168. {
  169.    int wait_count;
  170.    int port_base;
  171.  
  172.    port_base = prt->port_base;
  173.    while (!pr_ready (port_base))
  174.       {
  175.       for (wait_count = 0; wait_count < MAX_WAIT_POLL; wait_count++)
  176.          if (pr_ready (port_base))
  177.             break;
  178.       if (!pr_ready (port_base))
  179.          yield ();
  180.       }
  181.    tsk_outp (port_base + data, ch);
  182.    pr_toggle_strobe (port_base, prt->ccontrol);
  183. }
  184.  
  185.  
  186. local void Staticfunc pr_output_int (prtptr prt, byte ch)
  187. {
  188.    int wait_count;
  189.    int port_base;
  190.  
  191.    port_base = prt->port_base;
  192.    while (!pr_ready (port_base))
  193.       {
  194.       for (wait_count = 0; wait_count < MAX_WAIT_INT; wait_count++)
  195.          if (pr_ready (port_base))
  196.             break;
  197.       if (!pr_ready (port_base))
  198.          yield ();
  199.       }
  200.  
  201.    clear_flag (&prt->pready);
  202.  
  203.    tsk_outp (port_base + data, ch);
  204.    pr_toggle_strobe (port_base, (byte)(prt->ccontrol | IRQENA));
  205.  
  206.    for (wait_count = 0; wait_count < MAX_WAIT_INT; wait_count++)
  207.       if (check_flag (&prt->pready))
  208.          return;
  209.  
  210.    if (wait_flag_set (&prt->pready, INT_TIMEOUT) < 0)
  211.       tsk_outp (prt->port_base + control, prt->ccontrol &= ~IRQENA);
  212. }
  213.  
  214.  
  215. local void Taskfunc pr_task (prtptr prt)
  216. {
  217.    int ch;
  218.  
  219.    while (1)
  220.       {
  221.       ch = read_pipe (&prt->xmit_pipe, 0L);
  222.       if (prt->polling)
  223.          pr_output_poll (prt, (byte)ch);
  224.       else
  225.          pr_output_int (prt, (byte)ch);
  226.       }
  227. }
  228.  
  229. /*-------------------------------------------------------------------------*/
  230.  
  231. local void Taskfunc prt_chain_remove (callchainptr chain)
  232. {
  233.    /* 
  234.       We just assume here that all local data is in the same segment.
  235.       This should be true for all compilers and memory models
  236.       unless you define an extremely low data threshold.
  237.    */
  238.    prt_remove_all ();
  239. }
  240.  
  241.  
  242. int Globalfunc prt_install (int port, byte polling, word prior,
  243.                               farptr xmitbuf, word xmitsize)
  244. {
  245.    prtptr prt;
  246.    int pbase;
  247.    intprocptr far *intptr;
  248. #if (TSK_NAMEPAR)
  249.    static char name [] = "PRTn";
  250.  
  251.    name [3] = (char)((port & 0x7f) + '0');
  252. #endif
  253.  
  254.    if (port & 0x80)
  255.       {
  256.       port &= 0x7f;
  257.       if (port > 4)
  258.          return -1; 
  259.       pbase = *((wordptr)(TMK_FP (0x40, port * 2 + 8)));
  260.       if (!pbase)
  261.          return -1;
  262.  
  263.       for (port = 0; port < PORTS; port++)
  264.          if (pr_port_descr [port].base == pbase)
  265.             break;
  266.       }
  267.  
  268.    if (port < 0 || port >= PORTS || !xmitsize || prt_installed [port])
  269.       return -1;
  270.  
  271.    prt = &prt_data [port];
  272.  
  273.    if (create_pipe (&prt->xmit_pipe, xmitbuf, xmitsize TN(name)) == LNULL)
  274.       retur